library(dplyr)
library(plyr)
library(ggplot2)
`%not in%` <- function (x, table) is.na(match(x, table, nomatch=NA_integer_))

Read in all the delta psi files (10 comparisons each)

For GSE4..

muscle_liver_4 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE41637/all_comp_musc_liv_dpsi/muscle_liver.deltapsi_deltapsi.tsv")
muscle_liver_4
muscle_brain_4 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE41637/all_comp_musc_brn_dpsi/muscle_brain.deltapsi_deltapsi.tsv")
muscle_heart_4 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE41637/all_comp_musc_hrt_dpsi/muscle_heart.deltapsi_deltapsi.tsv")
muscle_testes_4 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE41637/all_comp_musc_test_dpsi/muscle_testes.deltapsi_deltapsi.tsv")
liver_heart_4 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE41637/all_comp_liv_hrt_dpsi/liver_heart.deltapsi_deltapsi.tsv")
heart_brain_4 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE41637/all_comp_hrt_brn_dpsi/heart_brain.deltapsi_deltapsi.tsv")
heart_testes_4 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE41637/all_comp_hrt_test_dpsi/heart_testes.deltapsi_deltapsi.tsv")
testes_brain_4 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE41637/all_comp_test_brn_dpsi/testes_brain.deltapsi_deltapsi.tsv")
liver_testes_4 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE41637/all_comp_liv_test_dpsi/liver_testes.deltapsi_deltapsi.tsv")
liver_brain_4 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE41637/all_comp_liv_brn_dpsi/liver_brain.deltapsi_deltapsi.tsv")
full4 <- list(muscle_liver_4,muscle_brain_4,muscle_heart_4,muscle_testes_4,liver_heart_4,heart_brain_4,heart_testes_4,testes_brain_4,liver_testes_4,liver_brain_4) %>%
    Reduce(function(dtf1,dtf2) full_join(dtf1,dtf2,by=c("LSV ID","Gene ID","#Gene Name","Junctions coords","Exons coords","strand","chr")), .)
delta_psi4 <- full4 %>%
  select(starts_with("E(dPSI)")) %>%
  setNames(c("muscle_liver","muscle_brain","muscle_heart","muscle_testes","heart_liver","heart_brain","heart_testes","testes_brain","testes_liver","brain_liver"))
final4 <- data.frame(full4$`#Gene Name`,full4$`Gene ID`,full4$`LSV ID`,full4$A5SS.x,full4$A3SS.x,full4$ES.x,full4$`Junctions coords`,full4$`Exons coords`,full4$strand,full4$chr,delta_psi4)
colnames(final4) <- c("Gene Name","Gene ID","LSV ID","A5SS","A3SS","ES","Junction Coords","Exon Coords","strand","chr","muscle_liver","muscle_brain","muscle_heart","muscle_testes","liver_heart","heart_brain","heart_testes","testes_brain","liver_testes","liver_brain")
final4

For GSE5…

muscle_liver_5 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE53960/all_comp_musc_liv_dpsi/muscle_liver.deltapsi_deltapsi.tsv")
muscle_brain_5 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE53960/all_comp_musc_brn_dpsi/muscle_brain.deltapsi_deltapsi.tsv")
muscle_heart_5 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE53960/all_comp_musc_hrt_dpsi/muscle_heart.deltapsi_deltapsi.tsv")
muscle_testes_5 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE53960/all_comp_musc_test_dpsi/muscle_testes.deltapsi_deltapsi.tsv")
liver_heart_5 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE53960/all_comp_liv_hrt_dpsi/liver_heart.deltapsi_deltapsi.tsv")
heart_brain_5 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE53960/all_comp_hrt_brn_dpsi/heart_brain.deltapsi_deltapsi.tsv")
heart_testes_5 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE53960/all_comp_hrt_test_dpsi/heart_testes.deltapsi_deltapsi.tsv") 
testes_brain_5 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE53960/all_comp_test_brn_dpsi/testes_brain.deltapsi_deltapsi.tsv") 
liver_testes_5 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE53960/all_comp_liv_test_dpsi/liver_testes.deltapsi_deltapsi.tsv") 
liver_brain_5 <- fread("/homes/s1207699/data/rna/MAJIQ_analysis/rat/GSE53960/all_comp_liv_brn_dpsi/liver_brain.deltapsi_deltapsi.tsv")
full5 <- list(muscle_liver_5,muscle_brain_5,muscle_heart_5,muscle_testes_5,liver_heart_5,heart_brain_5,heart_testes_5,testes_brain_5,liver_testes_5,liver_brain_5) %>%
    Reduce(function(dtf1,dtf2) full_join(dtf1,dtf2,by=c("LSV ID","Gene ID","#Gene Name","Junctions coords","Exons coords","strand","chr")), .)
delta_psi5 <- full5 %>%
  select(starts_with("E(dPSI)")) %>%
  setNames(c("muscle_liver","muscle_brain","muscle_heart","muscle_testes","liver_heart","heart_brain","heart_testes","testes_brain","liver_testes","liver_brain"))
final5 <- data.frame(full5$`#Gene Name`,full5$`Gene ID`,full5$`LSV ID`,full5$A5SS.x,full5$A3SS.x,full5$ES.x,full5$`Junctions coords`,full5$`Exons coords`,full5$strand,full5$chr,delta_psi5)
colnames(final5) <- c("Gene Name","Gene ID","LSV ID","A5SS","A3SS","ES","Junction Coords","Exon Coords","strand","chr","muscle_liver","muscle_brain","muscle_heart","muscle_testes","liver_heart","heart_brain","heart_testes","testes_brain","liver_testes","liver_brain")
final5
# Find LSVs that are present in both experiments
final_lsvs <- final5[final4$`LSV ID` %in% final5$`LSV ID`,]
final_lsvs <- unique(final_lsvs)
nrow(final_lsvs)
[1] 1662
length(unique(final_lsvs$`Gene ID`))
[1] 1154
final_lsvs
final_lsvs[is.na(final_lsvs)] <- 0
invalid factor level, NA generatedinvalid factor level, NA generatedinvalid factor level, NA generatedinvalid factor level, NA generatedinvalid factor level, NA generatedinvalid factor level, NA generatedinvalid factor level, NA generated
final4[is.na(final4)] <- 0
final5[is.na(final5)] <- 0
final_lsvs[1000:1900,]
fwrite(final_lsvs,file="/homes/s1207699/data/rna/MAJIQ_analysis/rat/high_confidence_lsvs.tsv",sep="\t")
# Enrichment for GSE4
rat_ne_nets = read.csv("/homes/s1207699/stuff_fromeric/RAT_NEMMnetlist_nets.bed", sep="\t", header=TRUE)
rat_ne_nets_names = unique(rat_ne_nets$rat)
rat_ne_nets_names[[1]]
[1] ENSRNOG00000031033
2963 Levels: ENSRNOG00000000048 ENSRNOG00000000066 ENSRNOG00000000081 ENSRNOG00000000082 ENSRNOG00000000104 ... ENSRNOG00000040287
mgenes <- fread("/homes/s1207699/data/RAT_muscle_gse4_exprs.txt")
lgenes <- fread("/homes/s1207699/data/RAT_liver_gse4_exprs.txt")
tgenes <- fread("/homes/s1207699/data/RAT_testes_gse4_exprs.txt")
bgenes <- fread("/homes/s1207699/data/RAT_brain_gse4_exprs.txt")
hgenes <- fread("/homes/s1207699/data/RAT_heart_gse4_exprs.txt")
all_genes <- Reduce(union, list(mgenes,lgenes,tgenes,bgenes,hgenes))
all_genes <- unique(union(all_genes[[1]],unique(final4$`Gene ID`)))
# How many rat-genes are NE > MM NETs
exprs_nets <- sum(unique(all_genes) %in% unique(rat_ne_nets_names))
length(exprs_nets)
[1] 1
# How many non-NET genes expressed
exprs_non_nets <- sum(unique(all_genes) %not in% unique(rat_ne_nets_names))
# The number of spliced NETs
s_genes <- unique(final4$`Gene ID`)
changed_all_nets = s_genes[which(s_genes %in% rat_ne_nets_names)]
splice_nets <- length(unique(changed_all_nets))
# Number of spliced non-nets
yy = s_genes[which(s_genes %not in% rat_ne_nets_names)]
length(unique(yy))+length(unique(changed_all_nets)) == length(unique(final4$`Gene ID`))
[1] TRUE
nrow(changed_all_nets)
NULL
splice_non_nets <- length(unique(yy))
# Fisher's exact test 
all_splicing <-
matrix(c(splice_nets, exprs_nets-splice_nets,splice_non_nets, exprs_non_nets-splice_non_nets),
       nrow = 2,
       dimnames =
       list(c("Spliced","Not spliced (but expressed)"),
            c("NET", "Non-NET")))
all_splicing
                             NET Non-NET
Spliced                      907    2960
Not spliced (but expressed) 1767    8159
fisher.test(all_splicing, alternative = "greater")

    Fisher's Exact Test for Count Data

data:  all_splicing
p-value = 6.097e-14
alternative hypothesis: true odds ratio is greater than 1
95 percent confidence interval:
 1.309922      Inf
sample estimates:
odds ratio 
  1.414848 
# Heatmap
heatmap <- data.frame(sapply(final_lsvs[,9:18], function(x)(length(na.omit(x)))))
tissue1 <- t(data.frame(stri_split_fixed(str=rownames(heatmap),pattern="_",n=3)))
heatmap3 <- data.frame(heatmap,tissue1[,1],tissue1[,2])
# I need to reorder the rows to make the heatmap look right, not sure how to do this in an elegant way
tissueone <- c(rep("brain",4),rep("heart",3),rep("liver",2),"muscle")
tissuetwo <- c("heart","liver","muscle","testes","liver","muscle","testes","muscle","testes","testes")
tissuelsvs <- c(473,237,396,884,176,168,687,170,364,602)
heatmap2 <- data.frame(tissueone,tissuetwo,tissuelsvs,stringsAsFactors = FALSE)
# Adapting code from http://pseudofish.com/triangle-heatmaps-in-r-using-ggplot.html
all_heatmap <- ggplot(heatmap2, aes(heatmap2$tissuetwo, heatmap2$tissueone)) +
    ggtitle('Number of changing LSVs in all genes between rat tissues') +
    theme_bw() +
    xlab(NULL) +
    ylab(NULL) +
    geom_tile(aes(fill = heatmap2$tissuelsvs), color='white') +
    scale_fill_gradient(low = 'lightyellow', high = 'red', space = 'Lab') +
    geom_text(aes(label = heatmap2$tissuelsvs)) +
    theme(legend.title = element_blank()) +
    theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) +
    theme(axis.text.x=element_text(angle=90),
          axis.ticks=element_blank(),
          axis.line=element_blank(),
          panel.border=element_blank())
all_heatmap

ggplot(data = heatmap2, aes(x=heatmap2$tissueone, y=heatmap2$tissuetwo, fill=heatmap2$tissuelsvs)) + 
  geom_tile()

# Get NET LSVs so we can make NET heatmap
net_lsvs <- final_lsvs[final_lsvs$`Gene ID` %in% rat_ne_nets_names,]
length(unique(net_lsvs$`Gene Name`))
[1] 327
# NET Heatmap
NETheatmap <- data.frame(sapply(net_lsvs[,9:18], function(x)(length(na.omit(x)))))
tissue1 <- t(data.frame(stri_split_fixed(str=rownames(NETheatmap),pattern="_",n=3)))
heatmap4 <- data.frame(NETheatmap,tissue1[,1],tissue1[,2])
heatmap4
# I need to reorder the rows to make the heatmap look right, not sure how to do this in an elegant way
tissueone <- c(rep("brain",4),rep("heart",3),rep("liver",2),"muscle")
tissuetwo <- c("heart","liver","muscle","testes","liver","muscle","testes","muscle","testes","testes")
tissuelsvs <- c(149,56,127,276,47,50,212,45,110,180)
netheatmap2 <- data.frame(tissueone,tissuetwo,tissuelsvs,stringsAsFactors = FALSE)
netheatmapfinal <- data.frame(netheatmap2$tissueone, netheatmap2$tissuetwo,round(netheatmap2$tissuelsvs/heatmap2$tissuelsvs,2))
netheatmapfinal
# Adapting code from http://pseudofish.com/triangle-heatmaps-in-r-using-ggplot.html
all_heatmap <- ggplot(netheatmapfinal, aes(netheatmapfinal$netheatmap2.tissuetwo, netheatmapfinal$netheatmap2.tissueone)) +
    ggtitle('Number of changing LSVs in all genes between rat tissues') +
    theme_bw() +
    xlab(NULL) +
    ylab(NULL) +
    geom_tile(aes(fill = netheatmapfinal[[3]]), color='white') +
    scale_fill_gradient(low = 'lightyellow', high = 'red', space = 'Lab') +
    geom_text(aes(label = netheatmapfinal[[3]])) +
    theme(legend.title = element_blank()) +
    theme(panel.grid.major = element_blank(), panel.grid.minor = element_blank()) +
    theme(axis.text.x=element_text(angle=90),
          axis.ticks=element_blank(),
          axis.line=element_blank(),
          panel.border=element_blank())
all_heatmap

final_lsvs %>% filter(is.na(`Junction Coords`))
final4 %>% filter(is.na(`Junction Coords`))
final_lsvs
fwrite(final_lsvs, file="/homes/s1207699/data/rna/MAJIQ_analysis/rat/final_lsvs.tsv")
fwrite(final4, file="/homes/s1207699/data/rna/MAJIQ_analysis/rat/final_lsvs_4.tsv")
fwrite(final5, file="/homes/s1207699/data/rna/MAJIQ_analysis/rat/final_lsvs_5.tsv")
# Go analysis
# Genes in LSVs that were found for both GSE5 and GSE4
genes <- paste0(unique(final_lsvs$`Gene Name`))
filEConn<-file("/homes/s1207699/data/rna/rat_merge_genes_0.2")
writeLines(genes, filEConn)
close(filEConn)
length(genes) #1154 genes identified as the same between gse4 and gse5
[1] 1154
go <- fread("/homes/s1207699/rat_merge_all_GO_results")
go$ANNOTATED_GENES <- strsplit(go$ANNOTATED_GENES,", ")
hello <- vector()
for (i in 1:(nrow(go)-1)){
  y = union(go$ANNOTATED_GENES[[i]],go$ANNOTATED_GENES[[i+1]])
  hello = union(hello,y)
}
hello = unique(final_lsvs$`Gene Name`)
#hello equals all the genes included in the GO analysis
upset_counts <- data.frame(hello)
for (x in 1:nrow(go)){
  p = vector()
  for (i in 1:length(hello)){
    if(hello[i] %in% go$ANNOTATED_GENES[[x]]){
      z = 1
    }
    else{
      z = 0
    }
    p = c(p,z)
  }
  upset_counts[,x+1] = p
}
colnames(upset_counts) <- c("gene",go$TERM)
# Make upset plot
library(UpSetR)
library(data.table)
library(cowplot)
upset_counts
upset(upset_counts,nsets=10,order.by ="freq", main.bar.color = "#722c6b")

upset(upset_counts,nsets=5,order.by ="freq", main.bar.color = "#722c6b")

LS0tCnRpdGxlOiAicmF0IHNwbGljaW5nIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKLS0tCgoKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkocGx5cikKbGlicmFyeShnZ3Bsb3QyKQpgJW5vdCBpbiVgIDwtIGZ1bmN0aW9uICh4LCB0YWJsZSkgaXMubmEobWF0Y2goeCwgdGFibGUsIG5vbWF0Y2g9TkFfaW50ZWdlcl8pKQoKYGBgCgpSZWFkIGluIGFsbCB0aGUgZGVsdGEgcHNpIGZpbGVzICgxMCBjb21wYXJpc29ucyBlYWNoKQoKRm9yIEdTRTQuLgoKYGBge3J9Cm11c2NsZV9saXZlcl80IDwtIGZyZWFkKCIvaG9tZXMvczEyMDc2OTkvZGF0YS9ybmEvTUFKSVFfYW5hbHlzaXMvcmF0L0dTRTQxNjM3L2FsbF9jb21wX211c2NfbGl2X2Rwc2kvbXVzY2xlX2xpdmVyLmRlbHRhcHNpX2RlbHRhcHNpLnRzdiIpCm11c2NsZV9saXZlcl80Cm11c2NsZV9icmFpbl80IDwtIGZyZWFkKCIvaG9tZXMvczEyMDc2OTkvZGF0YS9ybmEvTUFKSVFfYW5hbHlzaXMvcmF0L0dTRTQxNjM3L2FsbF9jb21wX211c2NfYnJuX2Rwc2kvbXVzY2xlX2JyYWluLmRlbHRhcHNpX2RlbHRhcHNpLnRzdiIpCm11c2NsZV9oZWFydF80IDwtIGZyZWFkKCIvaG9tZXMvczEyMDc2OTkvZGF0YS9ybmEvTUFKSVFfYW5hbHlzaXMvcmF0L0dTRTQxNjM3L2FsbF9jb21wX211c2NfaHJ0X2Rwc2kvbXVzY2xlX2hlYXJ0LmRlbHRhcHNpX2RlbHRhcHNpLnRzdiIpCm11c2NsZV90ZXN0ZXNfNCA8LSBmcmVhZCgiL2hvbWVzL3MxMjA3Njk5L2RhdGEvcm5hL01BSklRX2FuYWx5c2lzL3JhdC9HU0U0MTYzNy9hbGxfY29tcF9tdXNjX3Rlc3RfZHBzaS9tdXNjbGVfdGVzdGVzLmRlbHRhcHNpX2RlbHRhcHNpLnRzdiIpCmxpdmVyX2hlYXJ0XzQgPC0gZnJlYWQoIi9ob21lcy9zMTIwNzY5OS9kYXRhL3JuYS9NQUpJUV9hbmFseXNpcy9yYXQvR1NFNDE2MzcvYWxsX2NvbXBfbGl2X2hydF9kcHNpL2xpdmVyX2hlYXJ0LmRlbHRhcHNpX2RlbHRhcHNpLnRzdiIpCmhlYXJ0X2JyYWluXzQgPC0gZnJlYWQoIi9ob21lcy9zMTIwNzY5OS9kYXRhL3JuYS9NQUpJUV9hbmFseXNpcy9yYXQvR1NFNDE2MzcvYWxsX2NvbXBfaHJ0X2Jybl9kcHNpL2hlYXJ0X2JyYWluLmRlbHRhcHNpX2RlbHRhcHNpLnRzdiIpCmhlYXJ0X3Rlc3Rlc180IDwtIGZyZWFkKCIvaG9tZXMvczEyMDc2OTkvZGF0YS9ybmEvTUFKSVFfYW5hbHlzaXMvcmF0L0dTRTQxNjM3L2FsbF9jb21wX2hydF90ZXN0X2Rwc2kvaGVhcnRfdGVzdGVzLmRlbHRhcHNpX2RlbHRhcHNpLnRzdiIpCnRlc3Rlc19icmFpbl80IDwtIGZyZWFkKCIvaG9tZXMvczEyMDc2OTkvZGF0YS9ybmEvTUFKSVFfYW5hbHlzaXMvcmF0L0dTRTQxNjM3L2FsbF9jb21wX3Rlc3RfYnJuX2Rwc2kvdGVzdGVzX2JyYWluLmRlbHRhcHNpX2RlbHRhcHNpLnRzdiIpCmxpdmVyX3Rlc3Rlc180IDwtIGZyZWFkKCIvaG9tZXMvczEyMDc2OTkvZGF0YS9ybmEvTUFKSVFfYW5hbHlzaXMvcmF0L0dTRTQxNjM3L2FsbF9jb21wX2xpdl90ZXN0X2Rwc2kvbGl2ZXJfdGVzdGVzLmRlbHRhcHNpX2RlbHRhcHNpLnRzdiIpCmxpdmVyX2JyYWluXzQgPC0gZnJlYWQoIi9ob21lcy9zMTIwNzY5OS9kYXRhL3JuYS9NQUpJUV9hbmFseXNpcy9yYXQvR1NFNDE2MzcvYWxsX2NvbXBfbGl2X2Jybl9kcHNpL2xpdmVyX2JyYWluLmRlbHRhcHNpX2RlbHRhcHNpLnRzdiIpCgpmdWxsNCA8LSBsaXN0KG11c2NsZV9saXZlcl80LG11c2NsZV9icmFpbl80LG11c2NsZV9oZWFydF80LG11c2NsZV90ZXN0ZXNfNCxsaXZlcl9oZWFydF80LGhlYXJ0X2JyYWluXzQsaGVhcnRfdGVzdGVzXzQsdGVzdGVzX2JyYWluXzQsbGl2ZXJfdGVzdGVzXzQsbGl2ZXJfYnJhaW5fNCkgJT4lCiAgICBSZWR1Y2UoZnVuY3Rpb24oZHRmMSxkdGYyKSBmdWxsX2pvaW4oZHRmMSxkdGYyLGJ5PWMoIkxTViBJRCIsIkdlbmUgSUQiLCIjR2VuZSBOYW1lIiwiSnVuY3Rpb25zIGNvb3JkcyIsIkV4b25zIGNvb3JkcyIsInN0cmFuZCIsImNociIpKSwgLikKZGVsdGFfcHNpNCA8LSBmdWxsNCAlPiUKICBzZWxlY3Qoc3RhcnRzX3dpdGgoIkUoZFBTSSkiKSkgJT4lCiAgc2V0TmFtZXMoYygibXVzY2xlX2xpdmVyIiwibXVzY2xlX2JyYWluIiwibXVzY2xlX2hlYXJ0IiwibXVzY2xlX3Rlc3RlcyIsImhlYXJ0X2xpdmVyIiwiaGVhcnRfYnJhaW4iLCJoZWFydF90ZXN0ZXMiLCJ0ZXN0ZXNfYnJhaW4iLCJ0ZXN0ZXNfbGl2ZXIiLCJicmFpbl9saXZlciIpKQpmaW5hbDQgPC0gZGF0YS5mcmFtZShmdWxsNCRgI0dlbmUgTmFtZWAsZnVsbDQkYEdlbmUgSURgLGZ1bGw0JGBMU1YgSURgLGZ1bGw0JEE1U1MueCxmdWxsNCRBM1NTLngsZnVsbDQkRVMueCxmdWxsNCRgSnVuY3Rpb25zIGNvb3Jkc2AsZnVsbDQkYEV4b25zIGNvb3Jkc2AsZnVsbDQkc3RyYW5kLGZ1bGw0JGNocixkZWx0YV9wc2k0KQpjb2xuYW1lcyhmaW5hbDQpIDwtIGMoIkdlbmUgTmFtZSIsIkdlbmUgSUQiLCJMU1YgSUQiLCJBNVNTIiwiQTNTUyIsIkVTIiwiSnVuY3Rpb24gQ29vcmRzIiwiRXhvbiBDb29yZHMiLCJzdHJhbmQiLCJjaHIiLCJtdXNjbGVfbGl2ZXIiLCJtdXNjbGVfYnJhaW4iLCJtdXNjbGVfaGVhcnQiLCJtdXNjbGVfdGVzdGVzIiwibGl2ZXJfaGVhcnQiLCJoZWFydF9icmFpbiIsImhlYXJ0X3Rlc3RlcyIsInRlc3Rlc19icmFpbiIsImxpdmVyX3Rlc3RlcyIsImxpdmVyX2JyYWluIikKCmZpbmFsNApgYGAKCkZvciBHU0U1Li4uCmBgYHtyfQptdXNjbGVfbGl2ZXJfNSA8LSBmcmVhZCgiL2hvbWVzL3MxMjA3Njk5L2RhdGEvcm5hL01BSklRX2FuYWx5c2lzL3JhdC9HU0U1Mzk2MC9hbGxfY29tcF9tdXNjX2xpdl9kcHNpL211c2NsZV9saXZlci5kZWx0YXBzaV9kZWx0YXBzaS50c3YiKQptdXNjbGVfYnJhaW5fNSA8LSBmcmVhZCgiL2hvbWVzL3MxMjA3Njk5L2RhdGEvcm5hL01BSklRX2FuYWx5c2lzL3JhdC9HU0U1Mzk2MC9hbGxfY29tcF9tdXNjX2Jybl9kcHNpL211c2NsZV9icmFpbi5kZWx0YXBzaV9kZWx0YXBzaS50c3YiKQptdXNjbGVfaGVhcnRfNSA8LSBmcmVhZCgiL2hvbWVzL3MxMjA3Njk5L2RhdGEvcm5hL01BSklRX2FuYWx5c2lzL3JhdC9HU0U1Mzk2MC9hbGxfY29tcF9tdXNjX2hydF9kcHNpL211c2NsZV9oZWFydC5kZWx0YXBzaV9kZWx0YXBzaS50c3YiKQptdXNjbGVfdGVzdGVzXzUgPC0gZnJlYWQoIi9ob21lcy9zMTIwNzY5OS9kYXRhL3JuYS9NQUpJUV9hbmFseXNpcy9yYXQvR1NFNTM5NjAvYWxsX2NvbXBfbXVzY190ZXN0X2Rwc2kvbXVzY2xlX3Rlc3Rlcy5kZWx0YXBzaV9kZWx0YXBzaS50c3YiKQpsaXZlcl9oZWFydF81IDwtIGZyZWFkKCIvaG9tZXMvczEyMDc2OTkvZGF0YS9ybmEvTUFKSVFfYW5hbHlzaXMvcmF0L0dTRTUzOTYwL2FsbF9jb21wX2xpdl9ocnRfZHBzaS9saXZlcl9oZWFydC5kZWx0YXBzaV9kZWx0YXBzaS50c3YiKQpoZWFydF9icmFpbl81IDwtIGZyZWFkKCIvaG9tZXMvczEyMDc2OTkvZGF0YS9ybmEvTUFKSVFfYW5hbHlzaXMvcmF0L0dTRTUzOTYwL2FsbF9jb21wX2hydF9icm5fZHBzaS9oZWFydF9icmFpbi5kZWx0YXBzaV9kZWx0YXBzaS50c3YiKQpoZWFydF90ZXN0ZXNfNSA8LSBmcmVhZCgiL2hvbWVzL3MxMjA3Njk5L2RhdGEvcm5hL01BSklRX2FuYWx5c2lzL3JhdC9HU0U1Mzk2MC9hbGxfY29tcF9ocnRfdGVzdF9kcHNpL2hlYXJ0X3Rlc3Rlcy5kZWx0YXBzaV9kZWx0YXBzaS50c3YiKSAKdGVzdGVzX2JyYWluXzUgPC0gZnJlYWQoIi9ob21lcy9zMTIwNzY5OS9kYXRhL3JuYS9NQUpJUV9hbmFseXNpcy9yYXQvR1NFNTM5NjAvYWxsX2NvbXBfdGVzdF9icm5fZHBzaS90ZXN0ZXNfYnJhaW4uZGVsdGFwc2lfZGVsdGFwc2kudHN2IikgCmxpdmVyX3Rlc3Rlc181IDwtIGZyZWFkKCIvaG9tZXMvczEyMDc2OTkvZGF0YS9ybmEvTUFKSVFfYW5hbHlzaXMvcmF0L0dTRTUzOTYwL2FsbF9jb21wX2xpdl90ZXN0X2Rwc2kvbGl2ZXJfdGVzdGVzLmRlbHRhcHNpX2RlbHRhcHNpLnRzdiIpIApsaXZlcl9icmFpbl81IDwtIGZyZWFkKCIvaG9tZXMvczEyMDc2OTkvZGF0YS9ybmEvTUFKSVFfYW5hbHlzaXMvcmF0L0dTRTUzOTYwL2FsbF9jb21wX2xpdl9icm5fZHBzaS9saXZlcl9icmFpbi5kZWx0YXBzaV9kZWx0YXBzaS50c3YiKQoKZnVsbDUgPC0gbGlzdChtdXNjbGVfbGl2ZXJfNSxtdXNjbGVfYnJhaW5fNSxtdXNjbGVfaGVhcnRfNSxtdXNjbGVfdGVzdGVzXzUsbGl2ZXJfaGVhcnRfNSxoZWFydF9icmFpbl81LGhlYXJ0X3Rlc3Rlc181LHRlc3Rlc19icmFpbl81LGxpdmVyX3Rlc3Rlc181LGxpdmVyX2JyYWluXzUpICU+JQogICAgUmVkdWNlKGZ1bmN0aW9uKGR0ZjEsZHRmMikgZnVsbF9qb2luKGR0ZjEsZHRmMixieT1jKCJMU1YgSUQiLCJHZW5lIElEIiwiI0dlbmUgTmFtZSIsIkp1bmN0aW9ucyBjb29yZHMiLCJFeG9ucyBjb29yZHMiLCJzdHJhbmQiLCJjaHIiKSksIC4pCmRlbHRhX3BzaTUgPC0gZnVsbDUgJT4lCiAgc2VsZWN0KHN0YXJ0c193aXRoKCJFKGRQU0kpIikpICU+JQogIHNldE5hbWVzKGMoIm11c2NsZV9saXZlciIsIm11c2NsZV9icmFpbiIsIm11c2NsZV9oZWFydCIsIm11c2NsZV90ZXN0ZXMiLCJsaXZlcl9oZWFydCIsImhlYXJ0X2JyYWluIiwiaGVhcnRfdGVzdGVzIiwidGVzdGVzX2JyYWluIiwibGl2ZXJfdGVzdGVzIiwibGl2ZXJfYnJhaW4iKSkKZmluYWw1IDwtIGRhdGEuZnJhbWUoZnVsbDUkYCNHZW5lIE5hbWVgLGZ1bGw1JGBHZW5lIElEYCxmdWxsNSRgTFNWIElEYCxmdWxsNSRBNVNTLngsZnVsbDUkQTNTUy54LGZ1bGw1JEVTLngsZnVsbDUkYEp1bmN0aW9ucyBjb29yZHNgLGZ1bGw1JGBFeG9ucyBjb29yZHNgLGZ1bGw1JHN0cmFuZCxmdWxsNSRjaHIsZGVsdGFfcHNpNSkKCmNvbG5hbWVzKGZpbmFsNSkgPC0gYygiR2VuZSBOYW1lIiwiR2VuZSBJRCIsIkxTViBJRCIsIkE1U1MiLCJBM1NTIiwiRVMiLCJKdW5jdGlvbiBDb29yZHMiLCJFeG9uIENvb3JkcyIsInN0cmFuZCIsImNociIsIm11c2NsZV9saXZlciIsIm11c2NsZV9icmFpbiIsIm11c2NsZV9oZWFydCIsIm11c2NsZV90ZXN0ZXMiLCJsaXZlcl9oZWFydCIsImhlYXJ0X2JyYWluIiwiaGVhcnRfdGVzdGVzIiwidGVzdGVzX2JyYWluIiwibGl2ZXJfdGVzdGVzIiwibGl2ZXJfYnJhaW4iKQoKZmluYWw1CgoKYGBgCgpgYGB7cn0KIyBGaW5kIExTVnMgdGhhdCBhcmUgcHJlc2VudCBpbiBib3RoIGV4cGVyaW1lbnRzCmZpbmFsX2xzdnMgPC0gZmluYWw1W2ZpbmFsNCRgTFNWIElEYCAlaW4lIGZpbmFsNSRgTFNWIElEYCxdCmZpbmFsX2xzdnMgPC0gdW5pcXVlKGZpbmFsX2xzdnMpCm5yb3coZmluYWxfbHN2cykKbGVuZ3RoKHVuaXF1ZShmaW5hbF9sc3ZzJGBHZW5lIElEYCkpCmZpbmFsX2xzdnMKZmluYWxfbHN2c1tpcy5uYShmaW5hbF9sc3ZzKV0gPC0gMApmaW5hbDRbaXMubmEoZmluYWw0KV0gPC0gMApmaW5hbDVbaXMubmEoZmluYWw1KV0gPC0gMApmaW5hbF9sc3ZzWzEwMDA6MTkwMCxdCmZ3cml0ZShmaW5hbF9sc3ZzLGZpbGU9Ii9ob21lcy9zMTIwNzY5OS9kYXRhL3JuYS9NQUpJUV9hbmFseXNpcy9yYXQvaGlnaF9jb25maWRlbmNlX2xzdnMudHN2IixzZXA9Ilx0IikKYGBgCgoKCmBgYHtyfQojIEVucmljaG1lbnQgZm9yIEdTRTQKcmF0X25lX25ldHMgPSByZWFkLmNzdigiL2hvbWVzL3MxMjA3Njk5L3N0dWZmX2Zyb21lcmljL1JBVF9ORU1NbmV0bGlzdF9uZXRzLmJlZCIsIHNlcD0iXHQiLCBoZWFkZXI9VFJVRSkKcmF0X25lX25ldHNfbmFtZXMgPSB1bmlxdWUocmF0X25lX25ldHMkcmF0KQpyYXRfbmVfbmV0c19uYW1lc1tbMV1dCm1nZW5lcyA8LSBmcmVhZCgiL2hvbWVzL3MxMjA3Njk5L2RhdGEvUkFUX211c2NsZV9nc2U0X2V4cHJzLnR4dCIpCmxnZW5lcyA8LSBmcmVhZCgiL2hvbWVzL3MxMjA3Njk5L2RhdGEvUkFUX2xpdmVyX2dzZTRfZXhwcnMudHh0IikKdGdlbmVzIDwtIGZyZWFkKCIvaG9tZXMvczEyMDc2OTkvZGF0YS9SQVRfdGVzdGVzX2dzZTRfZXhwcnMudHh0IikKYmdlbmVzIDwtIGZyZWFkKCIvaG9tZXMvczEyMDc2OTkvZGF0YS9SQVRfYnJhaW5fZ3NlNF9leHBycy50eHQiKQpoZ2VuZXMgPC0gZnJlYWQoIi9ob21lcy9zMTIwNzY5OS9kYXRhL1JBVF9oZWFydF9nc2U0X2V4cHJzLnR4dCIpCmFsbF9nZW5lcyA8LSBSZWR1Y2UodW5pb24sIGxpc3QobWdlbmVzLGxnZW5lcyx0Z2VuZXMsYmdlbmVzLGhnZW5lcykpCmFsbF9nZW5lcyA8LSB1bmlxdWUodW5pb24oYWxsX2dlbmVzW1sxXV0sdW5pcXVlKGZpbmFsNCRgR2VuZSBJRGApKSkKCgojIEhvdyBtYW55IHJhdC1nZW5lcyBhcmUgTkUgPiBNTSBORVRzCmV4cHJzX25ldHMgPC0gc3VtKHVuaXF1ZShhbGxfZ2VuZXMpICVpbiUgdW5pcXVlKHJhdF9uZV9uZXRzX25hbWVzKSkKbGVuZ3RoKGV4cHJzX25ldHMpCiMgSG93IG1hbnkgbm9uLU5FVCBnZW5lcyBleHByZXNzZWQKZXhwcnNfbm9uX25ldHMgPC0gc3VtKHVuaXF1ZShhbGxfZ2VuZXMpICVub3QgaW4lIHVuaXF1ZShyYXRfbmVfbmV0c19uYW1lcykpCgojIFRoZSBudW1iZXIgb2Ygc3BsaWNlZCBORVRzCnNfZ2VuZXMgPC0gdW5pcXVlKGZpbmFsNCRgR2VuZSBJRGApCmNoYW5nZWRfYWxsX25ldHMgPSBzX2dlbmVzW3doaWNoKHNfZ2VuZXMgJWluJSByYXRfbmVfbmV0c19uYW1lcyldCnNwbGljZV9uZXRzIDwtIGxlbmd0aCh1bmlxdWUoY2hhbmdlZF9hbGxfbmV0cykpCgojIE51bWJlciBvZiBzcGxpY2VkIG5vbi1uZXRzCnl5ID0gc19nZW5lc1t3aGljaChzX2dlbmVzICVub3QgaW4lIHJhdF9uZV9uZXRzX25hbWVzKV0KbGVuZ3RoKHVuaXF1ZSh5eSkpK2xlbmd0aCh1bmlxdWUoY2hhbmdlZF9hbGxfbmV0cykpID09IGxlbmd0aCh1bmlxdWUoZmluYWw0JGBHZW5lIElEYCkpCgpucm93KGNoYW5nZWRfYWxsX25ldHMpCnNwbGljZV9ub25fbmV0cyA8LSBsZW5ndGgodW5pcXVlKHl5KSkKCmBgYApgYGB7cn0KIyBGaXNoZXIncyBleGFjdCB0ZXN0IAphbGxfc3BsaWNpbmcgPC0KbWF0cml4KGMoc3BsaWNlX25ldHMsIGV4cHJzX25ldHMtc3BsaWNlX25ldHMsc3BsaWNlX25vbl9uZXRzLCBleHByc19ub25fbmV0cy1zcGxpY2Vfbm9uX25ldHMpLAogICAgICAgbnJvdyA9IDIsCiAgICAgICBkaW1uYW1lcyA9CiAgICAgICBsaXN0KGMoIlNwbGljZWQiLCJOb3Qgc3BsaWNlZCAoYnV0IGV4cHJlc3NlZCkiKSwKICAgICAgICAgICAgYygiTkVUIiwgIk5vbi1ORVQiKSkpCmFsbF9zcGxpY2luZwpmaXNoZXIudGVzdChhbGxfc3BsaWNpbmcsIGFsdGVybmF0aXZlID0gImdyZWF0ZXIiKQpgYGAKCmBgYHtyfQojIEhlYXRtYXAKaGVhdG1hcCA8LSBkYXRhLmZyYW1lKHNhcHBseShmaW5hbF9sc3ZzWyw5OjE4XSwgZnVuY3Rpb24oeCkobGVuZ3RoKG5hLm9taXQoeCkpKSkpCnRpc3N1ZTEgPC0gdChkYXRhLmZyYW1lKHN0cmlfc3BsaXRfZml4ZWQoc3RyPXJvd25hbWVzKGhlYXRtYXApLHBhdHRlcm49Il8iLG49MykpKQpoZWF0bWFwMyA8LSBkYXRhLmZyYW1lKGhlYXRtYXAsdGlzc3VlMVssMV0sdGlzc3VlMVssMl0pCgojIEkgbmVlZCB0byByZW9yZGVyIHRoZSByb3dzIHRvIG1ha2UgdGhlIGhlYXRtYXAgbG9vayByaWdodCwgbm90IHN1cmUgaG93IHRvIGRvIHRoaXMgaW4gYW4gZWxlZ2FudCB3YXkKdGlzc3Vlb25lIDwtIGMocmVwKCJicmFpbiIsNCkscmVwKCJoZWFydCIsMykscmVwKCJsaXZlciIsMiksIm11c2NsZSIpCnRpc3N1ZXR3byA8LSBjKCJoZWFydCIsImxpdmVyIiwibXVzY2xlIiwidGVzdGVzIiwibGl2ZXIiLCJtdXNjbGUiLCJ0ZXN0ZXMiLCJtdXNjbGUiLCJ0ZXN0ZXMiLCJ0ZXN0ZXMiKQp0aXNzdWVsc3ZzIDwtIGMoNDczLDIzNywzOTYsODg0LDE3NiwxNjgsNjg3LDE3MCwzNjQsNjAyKQpoZWF0bWFwMiA8LSBkYXRhLmZyYW1lKHRpc3N1ZW9uZSx0aXNzdWV0d28sdGlzc3VlbHN2cyxzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCgoKIyBBZGFwdGluZyBjb2RlIGZyb20gaHR0cDovL3BzZXVkb2Zpc2guY29tL3RyaWFuZ2xlLWhlYXRtYXBzLWluLXItdXNpbmctZ2dwbG90Lmh0bWwKYWxsX2hlYXRtYXAgPC0gZ2dwbG90KGhlYXRtYXAyLCBhZXMoaGVhdG1hcDIkdGlzc3VldHdvLCBoZWF0bWFwMiR0aXNzdWVvbmUpKSArCiAgICBnZ3RpdGxlKCdOdW1iZXIgb2YgY2hhbmdpbmcgTFNWcyBpbiBhbGwgZ2VuZXMgYmV0d2VlbiByYXQgdGlzc3VlcycpICsKICAgIHRoZW1lX2J3KCkgKwogICAgeGxhYihOVUxMKSArCiAgICB5bGFiKE5VTEwpICsKICAgIGdlb21fdGlsZShhZXMoZmlsbCA9IGhlYXRtYXAyJHRpc3N1ZWxzdnMpLCBjb2xvcj0nd2hpdGUnKSArCiAgICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICdsaWdodHllbGxvdycsIGhpZ2ggPSAncmVkJywgc3BhY2UgPSAnTGFiJykgKwogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGhlYXRtYXAyJHRpc3N1ZWxzdnMpKSArCiAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkpICsKICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT05MCksCiAgICAgICAgICBheGlzLnRpY2tzPWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgIGF4aXMubGluZT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBwYW5lbC5ib3JkZXI9ZWxlbWVudF9ibGFuaygpKQphbGxfaGVhdG1hcApnZ3Bsb3QoZGF0YSA9IGhlYXRtYXAyLCBhZXMoeD1oZWF0bWFwMiR0aXNzdWVvbmUsIHk9aGVhdG1hcDIkdGlzc3VldHdvLCBmaWxsPWhlYXRtYXAyJHRpc3N1ZWxzdnMpKSArIAogIGdlb21fdGlsZSgpCmBgYAoKYGBge3J9CiMgR2V0IE5FVCBMU1ZzIHNvIHdlIGNhbiBtYWtlIE5FVCBoZWF0bWFwCgpuZXRfbHN2cyA8LSBmaW5hbF9sc3ZzW2ZpbmFsX2xzdnMkYEdlbmUgSURgICVpbiUgcmF0X25lX25ldHNfbmFtZXMsXQpsZW5ndGgodW5pcXVlKG5ldF9sc3ZzJGBHZW5lIE5hbWVgKSkKCiMgTkVUIEhlYXRtYXAKTkVUaGVhdG1hcCA8LSBkYXRhLmZyYW1lKHNhcHBseShuZXRfbHN2c1ssOToxOF0sIGZ1bmN0aW9uKHgpKGxlbmd0aChuYS5vbWl0KHgpKSkpKQp0aXNzdWUxIDwtIHQoZGF0YS5mcmFtZShzdHJpX3NwbGl0X2ZpeGVkKHN0cj1yb3duYW1lcyhORVRoZWF0bWFwKSxwYXR0ZXJuPSJfIixuPTMpKSkKaGVhdG1hcDQgPC0gZGF0YS5mcmFtZShORVRoZWF0bWFwLHRpc3N1ZTFbLDFdLHRpc3N1ZTFbLDJdKQpoZWF0bWFwNAoKIyBJIG5lZWQgdG8gcmVvcmRlciB0aGUgcm93cyB0byBtYWtlIHRoZSBoZWF0bWFwIGxvb2sgcmlnaHQsIG5vdCBzdXJlIGhvdyB0byBkbyB0aGlzIGluIGFuIGVsZWdhbnQgd2F5CnRpc3N1ZW9uZSA8LSBjKHJlcCgiYnJhaW4iLDQpLHJlcCgiaGVhcnQiLDMpLHJlcCgibGl2ZXIiLDIpLCJtdXNjbGUiKQp0aXNzdWV0d28gPC0gYygiaGVhcnQiLCJsaXZlciIsIm11c2NsZSIsInRlc3RlcyIsImxpdmVyIiwibXVzY2xlIiwidGVzdGVzIiwibXVzY2xlIiwidGVzdGVzIiwidGVzdGVzIikKdGlzc3VlbHN2cyA8LSBjKDE0OSw1NiwxMjcsMjc2LDQ3LDUwLDIxMiw0NSwxMTAsMTgwKQpuZXRoZWF0bWFwMiA8LSBkYXRhLmZyYW1lKHRpc3N1ZW9uZSx0aXNzdWV0d28sdGlzc3VlbHN2cyxzdHJpbmdzQXNGYWN0b3JzID0gRkFMU0UpCm5ldGhlYXRtYXBmaW5hbCA8LSBkYXRhLmZyYW1lKG5ldGhlYXRtYXAyJHRpc3N1ZW9uZSwgbmV0aGVhdG1hcDIkdGlzc3VldHdvLHJvdW5kKG5ldGhlYXRtYXAyJHRpc3N1ZWxzdnMvaGVhdG1hcDIkdGlzc3VlbHN2cywyKSkKbmV0aGVhdG1hcGZpbmFsCgojIEFkYXB0aW5nIGNvZGUgZnJvbSBodHRwOi8vcHNldWRvZmlzaC5jb20vdHJpYW5nbGUtaGVhdG1hcHMtaW4tci11c2luZy1nZ3Bsb3QuaHRtbAphbGxfaGVhdG1hcCA8LSBnZ3Bsb3QobmV0aGVhdG1hcGZpbmFsLCBhZXMobmV0aGVhdG1hcGZpbmFsJG5ldGhlYXRtYXAyLnRpc3N1ZXR3bywgbmV0aGVhdG1hcGZpbmFsJG5ldGhlYXRtYXAyLnRpc3N1ZW9uZSkpICsKICAgIGdndGl0bGUoJ051bWJlciBvZiBjaGFuZ2luZyBMU1ZzIGluIGFsbCBnZW5lcyBiZXR3ZWVuIHJhdCB0aXNzdWVzJykgKwogICAgdGhlbWVfYncoKSArCiAgICB4bGFiKE5VTEwpICsKICAgIHlsYWIoTlVMTCkgKwogICAgZ2VvbV90aWxlKGFlcyhmaWxsID0gbmV0aGVhdG1hcGZpbmFsW1szXV0pLCBjb2xvcj0nd2hpdGUnKSArCiAgICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICdsaWdodHllbGxvdycsIGhpZ2ggPSAncmVkJywgc3BhY2UgPSAnTGFiJykgKwogICAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IG5ldGhlYXRtYXBmaW5hbFtbM11dKSkgKwogICAgdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSArCiAgICB0aGVtZShwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yID0gZWxlbWVudF9ibGFuaygpKSArCiAgICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9OTApLAogICAgICAgICAgYXhpcy50aWNrcz1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICBheGlzLmxpbmU9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgcGFuZWwuYm9yZGVyPWVsZW1lbnRfYmxhbmsoKSkKYWxsX2hlYXRtYXAKCmBgYAoKYGBge3J9CmZpbmFsX2xzdnMgJT4lIGZpbHRlcihpcy5uYShgSnVuY3Rpb24gQ29vcmRzYCkpCmZpbmFsNCAlPiUgZmlsdGVyKGlzLm5hKGBKdW5jdGlvbiBDb29yZHNgKSkKZmluYWxfbHN2cwpmd3JpdGUoZmluYWxfbHN2cywgZmlsZT0iL2hvbWVzL3MxMjA3Njk5L2RhdGEvcm5hL01BSklRX2FuYWx5c2lzL3JhdC9maW5hbF9sc3ZzLnRzdiIpCmZ3cml0ZShmaW5hbDQsIGZpbGU9Ii9ob21lcy9zMTIwNzY5OS9kYXRhL3JuYS9NQUpJUV9hbmFseXNpcy9yYXQvZmluYWxfbHN2c180LnRzdiIpCmZ3cml0ZShmaW5hbDUsIGZpbGU9Ii9ob21lcy9zMTIwNzY5OS9kYXRhL3JuYS9NQUpJUV9hbmFseXNpcy9yYXQvZmluYWxfbHN2c181LnRzdiIpCgpgYGAKCmBgYHtyfQojIEdvIGFuYWx5c2lzCiMgR2VuZXMgaW4gTFNWcyB0aGF0IHdlcmUgZm91bmQgZm9yIGJvdGggR1NFNSBhbmQgR1NFNApnZW5lcyA8LSBwYXN0ZTAodW5pcXVlKGZpbmFsX2xzdnMkYEdlbmUgTmFtZWApKQpmaWxFQ29ubjwtZmlsZSgiL2hvbWVzL3MxMjA3Njk5L2RhdGEvcm5hL3JhdF9tZXJnZV9nZW5lc18wLjIiKQp3cml0ZUxpbmVzKGdlbmVzLCBmaWxFQ29ubikKY2xvc2UoZmlsRUNvbm4pCmxlbmd0aChnZW5lcykgIzExNTQgZ2VuZXMgaWRlbnRpZmllZCBhcyB0aGUgc2FtZSBiZXR3ZWVuIGdzZTQgYW5kIGdzZTUKCgpnbyA8LSBmcmVhZCgiL2hvbWVzL3MxMjA3Njk5L3JhdF9tZXJnZV9hbGxfR09fcmVzdWx0cyIpCmdvJEFOTk9UQVRFRF9HRU5FUyA8LSBzdHJzcGxpdChnbyRBTk5PVEFURURfR0VORVMsIiwgIikKaGVsbG8gPC0gdmVjdG9yKCkKZm9yIChpIGluIDE6KG5yb3coZ28pLTEpKXsKICB5ID0gdW5pb24oZ28kQU5OT1RBVEVEX0dFTkVTW1tpXV0sZ28kQU5OT1RBVEVEX0dFTkVTW1tpKzFdXSkKICBoZWxsbyA9IHVuaW9uKGhlbGxvLHkpCn0KCmhlbGxvID0gdW5pcXVlKGZpbmFsX2xzdnMkYEdlbmUgTmFtZWApCiNoZWxsbyBlcXVhbHMgYWxsIHRoZSBnZW5lcyBpbmNsdWRlZCBpbiB0aGUgR08gYW5hbHlzaXMKdXBzZXRfY291bnRzIDwtIGRhdGEuZnJhbWUoaGVsbG8pCmZvciAoeCBpbiAxOm5yb3coZ28pKXsKICBwID0gdmVjdG9yKCkKICBmb3IgKGkgaW4gMTpsZW5ndGgoaGVsbG8pKXsKICAgIGlmKGhlbGxvW2ldICVpbiUgZ28kQU5OT1RBVEVEX0dFTkVTW1t4XV0pewogICAgICB6ID0gMQogICAgfQogICAgZWxzZXsKICAgICAgeiA9IDAKICAgIH0KICAgIHAgPSBjKHAseikKICB9CiAgdXBzZXRfY291bnRzWyx4KzFdID0gcAp9CmNvbG5hbWVzKHVwc2V0X2NvdW50cykgPC0gYygiZ2VuZSIsZ28kVEVSTSkKCiMgTWFrZSB1cHNldCBwbG90CmxpYnJhcnkoVXBTZXRSKQpsaWJyYXJ5KGRhdGEudGFibGUpCmxpYnJhcnkoY293cGxvdCkKdXBzZXRfY291bnRzCnVwc2V0KHVwc2V0X2NvdW50cyxuc2V0cz0xMCxvcmRlci5ieSA9ImZyZXEiLCBtYWluLmJhci5jb2xvciA9ICIjNzIyYzZiIikKdXBzZXQodXBzZXRfY291bnRzLG5zZXRzPTUsb3JkZXIuYnkgPSJmcmVxIiwgbWFpbi5iYXIuY29sb3IgPSAiIzcyMmM2YiIpCmBgYAoK